use std::fmt;
use std::time::{Duration, Instant};

/// 进度状态跟踪器
#[derive(Debug, Clone, Copy)]
pub struct Progress {
    /// 已完成量
    pub completed: u64,
    /// 总量
    pub total: u64,
    /// 上次更新时间
    last_updated: Instant,
    /// 上次完成量
    last_completed: u64,
    /// 速度（单位/秒）
    pub speed: f64,
}

impl Progress {
    /// 创建新的进度跟踪器
    pub fn new(total: u64) -> Self {
        Progress {
            completed: 0,
            total,
            last_updated: Instant::now(),
            last_completed: 0,
            speed: 0.0,
        }
    }

    /// 更新进度
    pub fn update(&mut self, completed: u64) {
        self.completed = completed.min(self.total);
        self.calculate_speed();
    }

    /// 计算速度
    fn calculate_speed(&mut self) {
        let now = Instant::now();
        let duration = now.duration_since(self.last_updated);
        
        // 每0.5秒计算一次速度，避免频繁更新
        if duration >= Duration::from_millis(500) {
            let diff = self.completed - self.last_completed;
            self.speed = diff as f64 / duration.as_secs_f64();
            
            self.last_updated = now;
            self.last_completed = self.completed;
        }
    }

    /// 获取进度百分比
    pub fn percentage(&self) -> f32 {
        if self.total == 0 {
            0.0
        } else {
            (self.completed as f32 / self.total as f32) * 100.0
        }
    }

    /// 检查是否已完成
    pub fn is_complete(&self) -> bool {
        self.completed >= self.total
    }
}

/// 进度条显示
pub struct ProgressBar {
    progress: Progress,
    length: usize,
}

impl ProgressBar {
    /// 创建新的进度条
    pub fn new(total: u64, length: usize) -> Self {
        ProgressBar {
            progress: Progress::new(total),
            length,
        }
    }

    /// 更新进度条
    pub fn update(&mut self, completed: u64) {
        self.progress.update(completed);
    }

    /// 获取当前进度
    pub fn progress(&self) -> &Progress {
        &self.progress
    }
}

impl fmt::Display for ProgressBar {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let percent = self.progress.percentage();
        let filled = (percent / 100.0 * self.length as f32) as usize;
        let empty = self.length - filled;

        // 格式化速度显示
        let speed_str = if self.progress.speed < 1024.0 {
            format!("{:.1} B/s", self.progress.speed)
        } else if self.progress.speed < 1024.0 * 1024.0 {
            format!("{:.1} KB/s", self.progress.speed / 1024.0)
        } else {
            format!("{:.1} MB/s", self.progress.speed / (1024.0 * 1024.0))
        };

        // 格式化大小显示
        let completed_str = format_size(self.progress.completed);
        let total_str = format_size(self.progress.total);

        write!(
            f,
            "[{}{}] {:.1}% | {} / {} | {}",
            "=".repeat(filled),
            " ".repeat(empty),
            percent,
            completed_str,
            total_str,
            speed_str
        )
    }
}
/// 格式化字节大小显示
fn format_size(bytes: u64) -> String {
    // 定义所有需要的常量边界
    const MAX_B: u64 = 1023;
    const MIN_KB: u64 = 1024;
    const MAX_KB: u64 = 1048575;  // 1024*1024 - 1
    const MIN_MB: u64 = 1048576;  // 1024*1024
    const MAX_MB: u64 = 1073741823;  // 1024*1024*1024 - 1
    const MIN_GB: u64 = 1073741824;  // 1024*1024*1024

    match bytes {
        0..=MAX_B => format!("{} B", bytes),
        MIN_KB..=MAX_KB => format!("{:.1} KB", bytes as f64 / 1024.0),
        MIN_MB..=MAX_MB => format!("{:.1} MB", bytes as f64 / (1024.0 * 1024.0)),
        MIN_GB.. => format!("{:.1} GB", bytes as f64 / (1024.0 * 1024.0 * 1024.0)),
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_progress_percentage() {
        let mut progress = Progress::new(100);
        progress.update(50);
        assert_eq!(progress.percentage(), 50.0);
    }

    #[test]
    fn test_progress_complete() {
        let mut progress = Progress::new(100);
        progress.update(100);
        assert!(progress.is_complete());
    }

    #[test]
    fn test_format_size() {
        assert_eq!(format_size(512), "512 B");
        assert_eq!(format_size(1536), "1.5 KB");
        assert_eq!(format_size(2 * 1024 * 1024), "2.0 MB");
    }
}

